package com.sdp.irrigation.utils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

public class GPSUtil {
	public static double pi = 3.1415926535897932384626;
	public static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
	public static double a = 6378245.0;
	public static double ee = 0.00669342162296594323;
	private static final double EARTH_RADIUS = 6378137;//赤道半径(单位m)

	public static double transformLat(double x, double y) {
		double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
		return ret;
	}

	public static double transformLon(double x, double y) {
		double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
		return ret;
	}

	public static double[] transform(double lat, double lon) {
		if (outOfChina(lat, lon)) {
			return new double[] { lat, lon };
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new double[] { mgLat, mgLon };
	}

	public static boolean outOfChina(double lat, double lon) {
		if (lon < 72.004 || lon > 137.8347)
			return true;
		if (lat < 0.8293 || lat > 55.8271)
			return true;
		return false;
	}

	/**
	 * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
	 *
	 * @param lat 纬度
	 * @param lon 经度
	 * @return
	 */

	public static double[] gps84_To_Gcj02(double lat, double lon) {
		if (outOfChina(lat, lon)) {
			return new double[] { lat, lon };
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new double[] { mgLat, mgLon };
	}

	/**
	 * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
	 * 高德转GPS
	 */
	public static double[] gcj02_To_Gps84(double lat, double lon) {
		double[] gps = transform(lat, lon);
		double lontitude = lon * 2 - gps[1];
		double latitude = lat * 2 - gps[0];
		return new double[] { latitude, lontitude };
	}

	/**
	 * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
	 *
	 * @param lat
	 * @param lon
	 */
	public static double[] gcj02_To_Bd09(double lat, double lon) {
		double x = lon, y = lat;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
		double tempLon = z * Math.cos(theta) + 0.0065;
		double tempLat = z * Math.sin(theta) + 0.006;
		double[] gps = { tempLat, tempLon };
		return gps;
	}

	/**
	 * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 *
	 * * @param bd_lat * @param bd_lon * @return
	 */
	public static double[] bd09_To_Gcj02(double lat, double lon) {
		double x = lon - 0.0065, y = lat - 0.006;
		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
		double tempLon = z * Math.cos(theta);
		double tempLat = z * Math.sin(theta);
		double[] gps = { tempLat, tempLon };
		return gps;
	}

	/**
	 * 将gps84转为bd09
	 *
	 * @param lat
	 * @param lon
	 * @return
	 */
	public static double[] gps84_To_bd09(double lat, double lon) {
		double[] gcj02 = gps84_To_Gcj02(lat, lon);
		double[] bd09 = gcj02_To_Bd09(gcj02[0], gcj02[1]);
		return bd09;
	}

	public static double[] bd09_To_gps84(double lat, double lon) {
		double[] gcj02 = bd09_To_Gcj02(lat, lon);
		double[] gps84 = gcj02_To_Gps84(gcj02[0], gcj02[1]);
		// 保留小数点后六位
		gps84[0] = retain6(gps84[0]);
		gps84[1] = retain6(gps84[1]);
		return gps84;
	}

	/**
	 * 保留小数点后六位
	 *
	 * @param num
	 * @return
	 */
	private static double retain6(double num) {
		String result = String.format("%.6f", num);
		return Double.valueOf(result);
	}

	/**
	 * 根据轨迹点，构造区域
	 *
	 * @param points
	 */
	public static List<String> createArea(String points) {
		List<String> lineLs = new ArrayList<String>();
		String[] ps = points.split(";");
		double dx1 = 0.0D;
		double dy1 = 0.0D;
		double dx0 = 0.0D;
		double dy0 = 0.0D;
		for (int i = 1; i < ps.length; i++) {
			String[] cord1 = ps[i].split(",");
			dx1 = Double.parseDouble(cord1[0]);
			dy1 = Double.parseDouble(cord1[1]);

			String[] cord0 = ps[(i - 1)].split(",");
			dx0 = Double.parseDouble(cord0[0]);
			dy0 = Double.parseDouble(cord0[1]);

			Double[] line = new Double[4];
			line[0] = Double.valueOf(dx0);
			line[1] = Double.valueOf(dy0);
			line[2] = Double.valueOf(dx1);
			line[3] = Double.valueOf(dy1);
			lineLs.add(dx0 + "," + dy0 + "," + dx1 + "," + dy1);
		}
		return lineLs;
	}

	// 判断当前点是不是在该面积
	public static double getNearestDistance(List<String> lineLs, double x, double y, double width) {
		double r = 0.0D;
		for (int i = 0; i < lineLs.size(); i++) {
			String[] linePoints = lineLs.get(i).split(",");

			r = minDistenceOfPoint2Line(Double.parseDouble(linePoints[0]), Double.parseDouble(linePoints[1]),
					Double.parseDouble(linePoints[2]), Double.parseDouble(linePoints[3]), x, y);
			if (r <= width) {
				return r;
			}
		}

		return r;
	}

	public static double minDistenceOfPoint2Line(double x1, double y1, double x2, double y2, double x0, double y0) {
		double space = 0.0D;

		double a = computeLength(x1, y1, x2, y2);
		double b = computeLength(x1, y1, x0, y0);
		double c = computeLength(x2, y2, x0, y0);

		if ((c <= 1.0E-006D) || (b <= 1.0E-006D)) {
			space = 0.0D;
			return space;
		}

		if (a <= 1.0E-006D) {
			space = b;
			return space;
		}

		if (c * c >= a * a + b * b) {
			space = b;
			return space;
		}

		if (b * b >= a * a + c * c) {
			space = c;
			return space;
		}

		double p = (a + b + c) / 2.0D;
		double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));
		space = 2.0D * s / a;

		return space;
	}

	/**
	 * 根据两点间经纬度坐标（double值），计算两点间距离，单位为米
	 * @param dwStartX
	 * @param dwStartY
	 * @param dwEndX
	 * @param dwEndY
	 * @return
	 */
	public static double computeLength(double dwStartX, double dwStartY, double dwEndX, double dwEndY) {
		double PI = 3.1415926535898D;
		double latRadians1 = dwStartY * (PI / 180.0D);
		double latRadians2 = dwEndY * (PI / 180.0D);
		double latRadians = latRadians1 - latRadians2;
		double lngRadians = dwStartX * (PI / 180.0D) - dwEndX * (PI / 180.0D);
		double f = 2.0D * Math.asin(Math.sqrt(Math.pow(Math.sin(latRadians / 2.0D), 2.0D)
				+ Math.cos(latRadians1) * Math.cos(latRadians2) * Math.pow(Math.sin(lngRadians / 2.0D), 2.0D)));
		return f * 6378137.0D;
	}
	/**
	 * 转化为弧度(rad)
	 */
	private static double rad(double d) {
		return d * Math.PI / 180.0;
	}

	/**
	 * 基于余弦定理求两经纬度距离
	 * GPS地图坐标
	 * @param lon1 第一点的经度
	 * @param lat1 第一点的纬度
	 * @param lon2 第二点的经度
	 * @param lat2 第二点的纬度
	 * @return 返回的距离，单位km
	 */
	public static double LantitudeLongitudeDist(double lon1, double lat1, double lon2, double lat2) {
		double radLat1 = rad(lat1);
		double radLat2 = rad(lat2);

		double radLon1 = rad(lon1);
		double radLon2 = rad(lon2);

		if (radLat1 < 0)
			radLat1 = Math.PI / 2 + Math.abs(radLat1);// south
		if (radLat1 > 0)
			radLat1 = Math.PI / 2 - Math.abs(radLat1);// north
		if (radLon1 < 0)
			radLon1 = Math.PI * 2 - Math.abs(radLon1);// west
		if (radLat2 < 0)
			radLat2 = Math.PI / 2 + Math.abs(radLat2);// south
		if (radLat2 > 0)
			radLat2 = Math.PI / 2 - Math.abs(radLat2);// north
		if (radLon2 < 0)
			radLon2 = Math.PI * 2 - Math.abs(radLon2);// west
		double x1 = EARTH_RADIUS * Math.cos(radLon1) * Math.sin(radLat1);
		double y1 = EARTH_RADIUS * Math.sin(radLon1) * Math.sin(radLat1);

		double z1 = EARTH_RADIUS * Math.cos(radLat1);

		double x2 = EARTH_RADIUS * Math.cos(radLon2) * Math.sin(radLat2);
		double y2 = EARTH_RADIUS * Math.sin(radLon2) * Math.sin(radLat2);
		double z2 = EARTH_RADIUS * Math.cos(radLat2);

		double d = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
		//余弦定理求夹角
		double theta = Math.acos((EARTH_RADIUS * EARTH_RADIUS + EARTH_RADIUS * EARTH_RADIUS - d * d) / (2 * EARTH_RADIUS * EARTH_RADIUS));
		double dist = theta * EARTH_RADIUS;
		return dist;
	}
	/**
	 * 将经纬度 转换为 地址
	 *
	 * @param longitude 经度
	 * @param latitude  纬度
	 * @return 地址名称
	 * @throws Exception
	 */
	public static String getAddress(String longitude, String latitude){
		String url;
		try {
			url = "http://restapi.amap.com/v3/geocode/regeo?output=JSON&location=" + longitude + "," + latitude
					+ "&key=" + "2117e1ded95f613cb1244101d8c62f6d" + "&radius=0&extensions=base";

			// 高德接口返回的是JSON格式的字符串
			String queryResult = getResponse(url);
			if (ObjectUtils.isNull(queryResult)) {
				return "0";
			}

			// 将获取结果转为json 数据
			JSONObject obj = JSONObject.parseObject(queryResult);
			if (obj.get(GaoDeEnum.STATUS.getCode()).toString().equals(GaoDeEnum.INT_ONE.getCode())) {
				// 如果没有返回-1
				JSONObject reGeoCode = obj.getJSONObject(GaoDeEnum.RE_GEO_CODE.getCode());
				if (reGeoCode.size() > 0) {
					// 在regeocode中拿到 formatted_address 具体位置
					String formatted = reGeoCode.get("formatted_address").toString();
					return formatted;

				} else {
					return  "未找到相匹配的地址！";
				}
			} else {
				return "请求错误！";
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "系统未知异常，请稍后再试";
		}

	}

	/**
	 * 功能描述: 发送请求
	 *
	 * @param serverUrl 请求地址
	 * @return java.lang.String
	 * @author isymikasan
	 * @date 2022-01-26 09:15:01
	 */
	private static String getResponse(String serverUrl) {
		// 用JAVA发起http请求，并返回json格式的结果
		StringBuffer result = new StringBuffer();
		try {
			URL url = new URL(serverUrl);
			URLConnection conn = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result.append(line);
			}
			in.close();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result.toString();
	}



}
